package mygameserver;

import java.util.Vector;

public class GameLogic implements Subject {

    static int gameCounter = 0;
    private int[][] cells;
    private Vector<Observer> observers = new Vector<Observer>();
    private int resume = 0;     // -1 = can not be replayed  , 0  = can be , 1 = replayed
    private static final int BOARD_SIZE = 3;
    private static final int EMPTY_CELL = -1;
    private String lastCommand = "";
    private int winner = -1;  // -1 = continue game , 0 = nobody win , 1 = player1 , 2 = player2
    private int currentPlayerCode;
    private int code1;
    private int code2;
    private int gameIndex;

    public GameLogic() {
        cells = new int[BOARD_SIZE][BOARD_SIZE];
        gameIndex = gameCounter;
        gameCounter++;
    }

    public Vector<Observer> getObservers() {
        return observers;
    }

    public void eraseCells() {
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                cells[i][j] = EMPTY_CELL;
            }
        }
    }

    public void setCell(int i, int j, int cellType) {
        if (this.cells[i][j] == EMPTY_CELL) {
            this.cells[i][j] = cellType;

            if (this.checkNobodyWins()) {
                winner = 0;
            } else if (this.endOfGame()) {
                winner = currentPlayerCode;
            }

            if (currentPlayerCode == code1) {
                currentPlayerCode = code2;
            } else currentPlayerCode = code1;

            lastCommand = CommandsList.SET_CELL.getAbbr() + ";" + i + ";" + j + ";" + cellType + ";" + winner + ";" + currentPlayerCode + ";";
            stateChanged();
        }
    }

    public int isResume() {
        return resume;
    }

    public void setResume(int resume) {
        this.resume = resume;
    }

    public boolean endOfGame() {
        return checkColumn() || checkFDiagonal() || checkRow() || checkSDiagonal();
    }

    public boolean checkRow() {
        boolean res = false;
        for (int i = 0; i < BOARD_SIZE; i++) {
            int template = cells[i][0];
            for (int j = 0; j < BOARD_SIZE; j++) {
                res = template == cells[i][j] && template != EMPTY_CELL;
                if (!res) break;
            }
            if (res) break;
        }
        return res;
    }

    public boolean checkColumn() {
        boolean res = false;
        for (int i = 0; i < BOARD_SIZE; i++) {
            int template = cells[0][i];
            for (int j = 0; j < BOARD_SIZE; j++) {
                res = template == cells[j][i] && template != EMPTY_CELL;
                if (!res) break;
            }
            if (res) return res;
        }
        return res;
    }

    public boolean checkFDiagonal() {
        boolean res = false;
        int template = cells[0][0];
        for (int i = 0; i < BOARD_SIZE; i++) {
            res = template == cells[i][i] && template != EMPTY_CELL;
            if (!res) break;
        }
        return res;
    }

    public boolean checkSDiagonal() {
        boolean res = false;
        int j = BOARD_SIZE - 1;
        int template = cells[0][j];
        for (int i = 0; i < BOARD_SIZE; i++) {
            res = template == cells[j][i] && template != EMPTY_CELL;
            if (!res) break;
            j--;
        }
        return res;
    }

    public boolean checkNobodyWins() {
        boolean res = true;
        int template = EMPTY_CELL;
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                res = !(template == cells[j][i]);
                if (!res) break;
            }
            if (!res) return res;
        }
        return res;
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(lastCommand);
        }
    }

    public void stateChanged() {
        notifyObservers();
    }

    public void setStart() {
        code1 = ((Player) observers.get(0)).getpHashCode();
        code2 = ((Player) observers.get(1)).getpHashCode();
        currentPlayerCode = code1;
        lastCommand = CommandsList.START_GAME.getAbbr() + ";" + gameIndex + ";" + code1 + ";";
        this.eraseCells();
        winner = -1;
        stateChanged();
    }
}

